/**
 * @file   serializer.hpp
 * @author wolfhead <wolfhead@wolfhead-laptop>
 * @date   Wed Jul 20 11:29:00 2011
 * 
 * @brief  define serilaizer class which warp the strategy
 *         of how data is serialized
 */

#ifndef ACAPELLA_SERIALIZE_SERIALIZER_HPP
#define ACAPELLA_SERIALIZE_SERIALIZER_HPP

#include <string>
#include <map>

#include <acapella/traits/traits.h>
#include "serialize_strategy.hpp"

namespace acapella
{
namespace serialize
{

template<typename StreamType>
class serializer
{
public:
    serializer(StreamType& stream)
        :good_(true),stream_(stream)
    {
    }

    bool operator ! () const
    {
        return !good_;
    }

    operator bool () const
    {
        return good_;
    }

    bool good() const 
    {
        return good_;
    }

    bool bad() const
    {
        return !good_;
    }

    template<typename T>
    bool write(const T& value) 
    {
        return good_ = _write(value, stream_);
    }

    template<typename T>
    bool read(T& value)
    {
        return good_ = _read(value, stream_);
    }

    StreamType& stream() const
    {
        return stream_;
    }

    template<typename T>
    serializer& operator >> (T& value)
    {
        read(value);
        return *this;
    }

    template<typename T>
    serializer& operator << (const T& value)
    {
        write(value);
        return *this;
    }

private:
    template<typename T>
    bool _read(T& value, StreamType& stream)
    {
        return serialize_strategy<
            typename traits::is_pod<T>::type
                >::read(value, stream);
    }

    bool _read(std::string& str, StreamType& stream)
    {
        str.clear();

        size_t count = 0;
        if (!_read(count, stream))
        {
            return false;
        }

        str.reserve(count);
        char buffer[1024] = {0};

        if (!stream.read((char *)buffer, count))
        {
            return false;
        }
        str = buffer;
        return true;
    }

    template<typename T>
    bool _read(std::vector<T>& value, StreamType& stream)
    {
        value.clear();

        size_t count = 0;
        if (!_read(count, stream))
        {
            return false;
        }

        value.resize(count);
        for (size_t i = 0; i != count; ++i)
        {
            if (! _read(value[i], stream))
            {
                return false;
            }
        }
        return true;
    }

    template<typename KeyType, typename ValueType>
    bool _read(std::pair<KeyType, ValueType>& value, StreamType& stream)
    {
        if (!_read(value.first, stream))
        {
            return false;
        }

        if (!_read(value.second, stream))
        {
            return false;
        }
        return true;
    }


    template<typename KeyType, typename ValueType>
    bool _read(std::map<KeyType, ValueType>& value, StreamType& stream)
    {
        value.clear();
        size_t count = 0;
        if (!_read(count, stream))
        {
            return false;
        }

        std::pair<KeyType, ValueType> p;
        for (size_t i = 0; i != count; ++i)
        {
            if (!_read(p, stream))
            {
                return false;
            }
            value.insert(p);
        }
        return true;
    }


    template<typename T>
    bool _write(const T& value, StreamType& stream)
    {
        return serialize_strategy<
        typename traits::is_pod<T>::type
            >::write(value, stream);
    }

    
    bool _write(const std::string& str, StreamType& stream)
    {
        bool result = _write(str.size(), stream);
		stream.write(str.data(), str.size());
        result &= stream.good();

        return result;
    }

    template<typename T>
    bool _write(const std::vector<T>& value, StreamType& stream)
    {
        if (!_write(value.size(), stream))
        {
            return false;
        }

        for (size_t i = 0; i != value.size(); ++i)
        {
            if (!_write(value[i], stream))
            {
                return false;
            } 
        }
        return true;
    }

    template<typename KeyType, typename ValueType>
    bool _write(const std::pair<KeyType, ValueType>& value, StreamType& stream)
    {
        if (!_write(value.first, stream)) {return false;}
        if (!_write(value.second, stream)) {return false;}
        return true;
    }

    template<typename KeyType, typename ValueType>
    bool _write(const std::map<KeyType, ValueType>& value, StreamType& stream)
    {
        if (!_write(value.size(), stream))
        {
            return false;
        }

        for (typename std::map<KeyType, ValueType>::const_iterator it = value.begin();
             it != value.end();
             ++it)
        {
            if (!_write(*it, stream)) 
            {
                return false;
            }
        }
        return true;
    }


private:

    bool good_;
    StreamType& stream_;

    serializer(const serializer&);
    serializer& operator=(const serializer&);
}; 



}
}



#endif
